﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;
using System.Reflection;
using System.Xml.XPath;

namespace Jargon.Resources
{
    /// <summary>
    /// Reads the Jargon files and fills Jargons.
    /// <remarks>The Jargon files must reside in a directory below or at the same level
    /// that Jargon.Resources assembly resides.
    /// The Jargon files must have the extension ".jar.xml".
    /// The default Jargon used is the last one read</remarks>
    /// </summary>
    public class JargonReader
    {
        private static JargonReader instance = null;
        private string defaultJargon;
        private Dictionary<string, JargonCulture> cultures = null;
        private Dictionary<string, string> substitutes = null;

        public static string DefaultJargon
        {
            get { return instance.defaultJargon; }
            set { instance.defaultJargon = value; }
        }

        public static string[] JargonsSupported
        {
            get
            {
                string[] jargons = new string[instance.cultures.Keys.Count];

                Dictionary<string, JargonCulture>.Enumerator en = instance.cultures.GetEnumerator();
                int i = 0;
                while (en.MoveNext())
                {
                    jargons[i] = 
                        string.Format(
                            "{0} : {1}{2}", 
                            en.Current.Value.Description, 
                            en.Current.Value.Language,
                            string.IsNullOrEmpty(en.Current.Value.Substitution) ? 
                                string.Empty : 
                                ", " + en.Current.Value.Substitution);

                    i++;
                }
                return jargons;
            }
        }

        static JargonReader()
        {
            instance = new JargonReader();
        }

        private JargonReader()
        {
            cultures = new Dictionary<string, JargonCulture>();
            substitutes = new Dictionary<string, string>();
            readAllFiles();
        }

        /// <summary>
        /// Gets the string with the key specified for the specified Jargon
        /// </summary>
        /// <param name="languageCode">The language code of the Jargon</param>
        /// <param name="key">The key of the text to get</param>
        /// <param name="letterCase">The letter case of the string to retrieve</param>
        /// <returns>The text specified by the key, or the text specified by the key in default Jargon if 
        /// requested Jargon does not contain the key. Or %% NO VALUE %% if it the default Jargon does not 
        /// contain the key either</returns>
        public static string GetString(string languageCode, string key, JargonLetterCase letterCase)
        {
            return instance.GetString(languageCode, key, letterCase, instance.defaultJargon);
        }

        /// <summary>
        /// Gets the string with the key specified for one of the specified Jargons
        /// </summary>
        /// <param name="languages">The language codes of the Jargons</param>
        /// <param name="key">The key of the text to get</param>
        /// <param name="letterCase">The letter case of the string to retrieve</param>
        /// <returns>The text specified by the key, or the text specified by the key in default Jargon if 
        /// requested Jargon does not contain the key. Or %% NO VALUE %% if it the default Jargon does not 
        /// contain the key either</returns>
        /// <remarks>Jargons are searched for the key starting with the 0th index of languages array.
        /// If no array member contains the specified key, the default Jargon is used.</remarks>
        public static string GetString(string[] languages, string key, JargonLetterCase letterCase)
        {
            foreach (string language in languages)
            {
                if (instance.cultures.ContainsKey(language) || instance.substitutes.ContainsKey(language))
                {
                    return GetString(language, key, letterCase);
                }
            }
            return GetString(instance.defaultJargon, key, letterCase);
        }

        /// <summary>
        /// Gets the string with the key specified for the specified Jargon
        /// </summary>
        /// <param name="languageCode">The language code of the Jargon</param>
        /// <param name="key">The key of the text to get</param>
        /// <param name="letterCase">The letter case of the string to retrieve</param>
        /// <param name="defaultCulture">The default Jargon to use</param>
        /// <returns>The text specified by the key, or the text specified by the key in default Jargon if 
        /// requested Jargon does not contain the key. Or %% NO VALUE %% if it the default Jargon does not 
        /// contain the key either</returns>
        public string GetString(string languageCode, string key, JargonLetterCase letterCase, string defaultCulture)
        {
            string retval = "%% NO VALUE %%";

            if (string.IsNullOrEmpty(languageCode))
            {
                retval = "%% KEY NULL %%";
            }
            else if (cultures.ContainsKey(languageCode))
            {
                if (cultures[languageCode].Strings.ContainsKey(key))
                {
                    retval = transformString(cultures[languageCode].Strings[key], letterCase);
                }
            }
            else if (substitutes.ContainsKey(languageCode))
            {
                retval = GetString(substitutes[languageCode], key, letterCase, defaultCulture);
            }
            else if (cultures[defaultCulture].Strings.ContainsKey(key))
            {
                retval = GetString(defaultJargon, key, letterCase, defaultCulture);
            }
            return retval;
        }

        private string transformString(string str, JargonLetterCase letterCase)
        {
            string retval = str;
            switch (letterCase)
            {
                case JargonLetterCase.AllCapitals:
                    retval = str.ToUpper();
                    break;
                case JargonLetterCase.CapitalAllWords:
                    string temp = string.Empty;
                    for (int i = 0; i < retval.Length; i++)
                    {
                        if (i == 0 || retval[i - 1] == ' ')
                        {
                            temp += char.ToUpper(retval[i]);
                        }
                        else
                        {
                            temp += retval[i];
                        }
                    }
                    retval = temp;
                    break;
                case JargonLetterCase.CapitalFirstLetter:
                    retval = char.ToUpper(retval[0]) + retval.Substring(1);
                    break;
                case JargonLetterCase.NoCapitals:
                    retval = str.ToLower();
                    break;
            }
            return retval;
        }

        private void readAllFiles()
        {
            string currentDirectory = AppDomain.CurrentDomain.BaseDirectory;
            string[] cultureFiles = Directory.GetFiles(currentDirectory, "*.jar.xml", SearchOption.AllDirectories);
            foreach (string file in cultureFiles)
            {
                readFile(file);
            }
        }

        private void readFile(string file)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(file);

            XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
            nsManager.AddNamespace("jar", "urn:turk-isi.jargon");

            XmlNode root = doc.SelectSingleNode("/jar:jargon", nsManager);
            
            string language = root.Attributes["lang"].Value;
            string description = root.Attributes["name"].Value;
            string substitution = string.Empty;
            if (root.Attributes["substitutes"] != null)
            {
                substitution = root.Attributes["substitutes"].Value;
                substitutes.Add(substitution, language);
            }
            JargonCulture culture = new JargonCulture(language, description, substitution);

            XmlNodeList strings = root.SelectNodes("jar:string", nsManager);
            foreach (XmlNode node in strings)
            {
                string key = node.Attributes["name"].Value;
                string value = node.Attributes["value"].Value;
                culture.Strings.Add(key, value);
            }

            cultures.Add(language, culture);
            defaultJargon = language;
        }
    }
}
